include "dirent.h";
include "unistd.h";
include "sys/time.h";

abstract Directory: dirent {
    public static function read(path: Path): DirectoryReader {
        return DirectoryReader.new(path);
    }

    rules {
        ($this.path) => ($this.d_name as CString) as Path;
    }
}

abstract DirectoryReader: Ptr[DIR] {
    public static function new(path: Path) {
        return opendir(path) as DirectoryReader;
    }

    rules {
        (for $ident in $this {$e}) => {
            var __dir = $this;
            do {
                var __next: Ptr[Directory] = readdir(__dir) as Ptr[Directory];
                if __next == null {
                    break;
                } else {
                    var $ident = __next;
                    {$e}
                }
            } while true;
        }
    }
}

implement Iterable(Ptr[Directory]) for DirectoryReader {
    public function iterator(): Box[Iterator[Ptr[Directory]]] {
        return this;
    }
}

implement Iterator[Ptr[Directory]] for DirectoryReader {
    public function next(): (Box[Iterator[Ptr[Directory]]], Option[Ptr[Directory]]) {
        var dir = readdir(this) as Ptr[Directory];
        if dir != null {
            return (this, Some(dir));
        } else {
            return (this, None);
        }
    }
}
